package com.ruoyi.web.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.base.user.domain.Agent;
import com.ruoyi.common.base.user.domain.User;
import com.ruoyi.common.base.user.enums.UserEnum;
import com.ruoyi.common.base.user.mapper.AgentMapper;
import com.ruoyi.common.base.user.mapper.UserMapper;
import com.ruoyi.common.base.user.mapstruct.UserStruct;
import com.ruoyi.common.base.user.vo.UserLoginRes;
import com.ruoyi.common.base.user.vo.UserToken;
import com.ruoyi.common.constant.SysConfigConstants;
import com.ruoyi.common.customize.util.CommonUtil;
import com.ruoyi.common.customize.util.login.TokenUtil;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.web.service.IUserService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;

/**
 * 用户Service业务层处理
 *
 * @author gdk
 * @since 2023-05-15
 */
@Slf4j
@Service
@AllArgsConstructor
public class UserServiceImpl implements IUserService {
    private final UserMapper userMapper;
    private final AgentMapper agentMapper;

    private final CommonUtil commonUtil;
    private final ISysConfigService sysConfigService;
    private final TokenService tokenService;

    /**
     * 查询用户
     *
     * @param id 用户主键
     * @return 用户
     */
    @Override
    public User selectUserById(Long id) {
        return userMapper.selectUserById(id);
    }

    /**
     * 查询用户列表
     *
     * @param user 用户
     * @return 用户
     */
    @Override
    public List<User> selectUserList(User user) {
        return userMapper.selectUserList(user);
    }

    /**
     * 新增用户
     *
     * @param user 用户
     * @return 结果
     */
    @Override
    public int insertUser(User user) {
        user.setCreateTime(DateUtils.getNowDate());
        return userMapper.insertUser(user);
    }

    /**
     * 修改用户
     *
     * @param user 用户
     * @return 结果
     */
    @Override
    public int updateUser(User user) {
        user.setUpdateTime(DateUtils.getNowDate());
        return userMapper.updateUser(user);
    }

    /**
     * 批量删除用户
     *
     * @param ids 需要删除的用户主键
     * @return 结果
     */
    @Override
    public int deleteUserByIds(Long[] ids) {
        return userMapper.deleteUserByIds(ids);
    }

    /**
     * 删除用户信息
     *
     * @param id 用户主键
     * @return 结果
     */
    @Override
    public int deleteUserById(Long id) {
        return userMapper.deleteUserById(id);
    }

    /**
     * snsapi_userinfo注册
     *
     * @param code 微信用户临时授权code
     * @return {@link UserLoginRes}
     * @author gdk
     * @since 2023/5/22 19:53
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public UserLoginRes registryWechatCode(String code) {
        // code换取accessToken todo gdk
        /*JSONObject authRes = getAccessToken(code);
        // 根据openId尝试登录
        UserLoginRes res = loginWechatCode(authRes.getString("openid"));
        if (!Objects.isNull(res)) {
            return res;
        }*/

        UserLoginRes res = loginWechatCode(code);
        if (!Objects.isNull(res)) {
            return res;
        }

        // accessToken获取用户信息
        /*JSONObject userInfo = getUserInfo(authRes.getString("access_token"), authRes.getString("openid"));
        // 根据微信信息创建用户
        User user = createUser(userInfo);*/
        User user = new User();
        user.setOpenId(code);
        user.setUnionId(code);
        user.setNickname("测试用的昵称");
        user.setAvatar("https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg");
        // 0未知、1男、2女
        user.setSex("1");
        user.setRole(UserEnum.Role.NORMAL.getValue());
        user.setTrialNum(Integer.valueOf(sysConfigService.selectConfigByKey(SysConfigConstants.USER_TRIAL_NUM, "10")));
        commonUtil.initCreateAbout(user);
        user.setCreateBy(user.getId().toString());
        user.setUpdateBy(user.getCreateBy());
        if (userMapper.insertUser(user) != 1) {
            CommonUtil.throwError();
        }

        // 创建代理信息
        Agent agent = new Agent();
        agent.setId(user.getId());
        agent.setInviteNum(0);
        agent.setDividend(BigDecimal.ZERO);
        agent.setWithdrawal(BigDecimal.ZERO);
        agent.setFrozen(BigDecimal.ZERO);
        agent.setBalance(BigDecimal.ZERO);
        agent.setCreateBy(user.getCreateBy());
        agent.setUpdateBy(user.getCreateBy());
        commonUtil.initCreateAbout(agent);
        if (agentMapper.insertAgent(agent) != 1) {
            throw new ServiceException("新增用户代理信息失败");
        }

        UserToken userToken = UserStruct.INSTANCE.entity2Token(user);

        // 登录，生成token
        res = UserStruct.INSTANCE.token2LoginRes(userToken);
        res.setToken(tokenService.createToken(TokenUtil.createLoginUser(userToken)));

        return res;
    }

    /**
     * 根据微信信息创建用户
     *
     * @param userInfo 用户信息
     * @return {@link User}
     * @author gdk
     * @since 2023/5/22 20:51
     */
    public User createUser(JSONObject userInfo) {
        // 根据微信用户信息注册
        User user = new User();
        user.setOpenId(userInfo.getString("openid"));
        user.setUnionId(userInfo.getString("unionid"));
        user.setNickname(userInfo.getString("nickname"));
        user.setAvatar(userInfo.getString("headimgurl"));
        // 0未知、1男、2女
        user.setSex(userInfo.getString("sex"));
        user.setRole(UserEnum.Role.NORMAL.getValue());
        user.setTrialNum(Integer.valueOf(sysConfigService.selectConfigByKey(SysConfigConstants.USER_TRIAL_NUM, "10")));
        commonUtil.initCreateAbout(user);
        user.setCreateBy(user.getId().toString());
        user.setUpdateBy(user.getCreateBy());
        if (userMapper.insertUser(user) != 1) {
            CommonUtil.throwError();
        }

        // 创建代理信息
        Agent agent = new Agent();
        agent.setId(user.getId());
        agent.setInviteNum(0);
        agent.setDividend(BigDecimal.ZERO);
        agent.setWithdrawal(BigDecimal.ZERO);
        agent.setFrozen(BigDecimal.ZERO);
        agent.setBalance(BigDecimal.ZERO);
        commonUtil.initCreateAbout(agent);
        if (agentMapper.insertAgent(agent) != 1) {
            throw new ServiceException("新增用户代理信息失败");
        }

        return user;
    }

    /**
     * 获取用户信息
     *
     * @param accessToken accessToken
     * @param openId      openId
     * @return {@link JSONObject}
     * <pre>
     * {
     *   "openid": "OPENID",
     *   "nickname": NICKNAME,
     *   "sex": 1,
     *   "province":"PROVINCE",
     *   "city":"CITY",
     *   "country":"COUNTRY",
     *   "headimgurl":"https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
     *   "privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
     *   "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
     * }
     * </pre>
     * @author gdk
     * @since 2023/5/22 20:16
     */
    public JSONObject getUserInfo(String accessToken, String openId) {
        String url = String.format("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN",
                accessToken,
                openId);
        String resStr = HttpUtils.sendGet(url);
        JSONObject res = JSONObject.parseObject(resStr);

        String nickname = res.getString("nickname");
        if (Strings.isBlank(nickname)) {
            throw new ServiceException("获取微信用户信息失败");
        }

        return res;
    }

    /**
     * 用code获取accessToken
     *
     * @param code 微信用户临时授权code
     * @return {@link JSONObject}
     * <pre>
     * {
     *   "access_token":"ACCESS_TOKEN",
     *   "expires_in":7200,
     *   "refresh_token":"REFRESH_TOKEN",
     *   "openid":"OPENID",
     *   "scope":"SCOPE",
     *   "is_snapshotuser": 1,
     *   "unionid": "UNIONID"
     * }
     * </pre>
     * @author gdk
     * @since 2023/5/22 20:10
     */
    public JSONObject getAccessToken(String code) {
        /*String url = String.format("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
                wxMpConfigStorage.getAppId(),
                wxMpConfigStorage.getSecret(),
                code);
        String resStr = HttpUtils.sendGet(url);
        JSONObject res = JSONObject.parseObject(resStr);

        // 判断是否请求失败
        String errCode = res.getString("errcode");
        if (Strings.isNotBlank(errCode)) {
            log.error("使用微信临时授权code获取accessToken失败：[errorCode: {}, errorMsg: {}]",
                    errCode,
                    res.getString("errmsg"));

            throw new ServiceException("微信服务器请求失败，请重试");
        }

        // 是否为快照页模式虚拟账号
        String isSnapshotUser = res.getString("is_snapshotuser");
        if ("1".equals(isSnapshotUser)) {
            throw new ServiceException("请使用真实的账号信息");
        }

        String accessToken = res.getString("access_token");
        String openId = res.getString("openid");
        if (Strings.isBlank(accessToken) || Strings.isBlank(openId)) {
            throw new ServiceException("未能正确获得微信授权，请重试");
        }

        return res;*/
        return null;
    }

    /**
     * snsapi_base尝试登录
     *
     * @param code 微信用户临时授权code
     * @return {@link UserLoginRes}
     * @author gdk
     * @since 2023/5/22 21:23
     */
    @Override
    public UserLoginRes loginWechatCode(String code) {
        // code换取accessToken todo gdk
        // JSONObject authRes = getAccessToken(code);
        // String openId = authRes.getString("openid");
        String openId = code;
        // 根据openId查询用户
        User user = userMapper.getUserByOpenId(openId);
        if (Objects.isNull(user)) {
            return null;
        }

        // 组装token信息
        UserToken token = getUserToken(user);
        UserLoginRes res = UserStruct.INSTANCE.token2LoginRes(token);
        res.setToken(tokenService.createToken(TokenUtil.createLoginUser(token)));

        return res;
    }

    /**
     * 根据用户信息组装登录token信息
     *
     * @param user 用户
     * @return {@link UserToken}
     * @author gdk
     * @since 2023/5/26 14:57
     */
    public UserToken getUserToken(User user) {
        return UserStruct.INSTANCE.entity2Token(user);
    }
}
